import { isValid, Layers, Node, Prefab, sp, Sprite, SpriteFrame, v3 } from 'cc';
import { ecsclass, EcsComponent } from 'db://pkg/@gamex/cc-ecs';

export enum RenderType {
    None,
    Texture,
    Spine,
    Prefab
}

export interface IRenderReadonly {
    readonly uuid: number
    readonly isValid: boolean
    readonly ecsName: string
    readonly allowMultiple: boolean
    readonly allowRecycling: boolean

    readonly refreshRender: boolean
    readonly refreshRenderAttr: boolean
    readonly refreshSpineAnimation: boolean
    readonly refreshSpineSkin: boolean
}

@ecsclass('RenderComponent')
export class RenderComponent extends EcsComponent {
    static allowMultiple: boolean = true;
    static allowRecycling: boolean = true;

    private _refreshAttr = true;
    /**刷新通用属性 */
    public get refreshAttr() {
        return this._refreshAttr;
    }

    private _refreshRender = true;
    /**刷新渲染 */
    public get refreshRender() {
        return this._refreshRender;
    }

    private _refreshRenderAttr = true;
    /**刷新渲染属性 */
    public get refreshRenderAttr() {
        return this._refreshRenderAttr;
    }

    private _refreshSpineAnimation = true;
    /**刷新spine动画 */
    public get refreshSpineAnimation() {
        return this._refreshSpineAnimation;
    }

    private _refreshSpineSkin = true;
    /**刷新spine皮肤 */
    public get refreshSpineSkin() {
        return this._refreshSpineSkin;
    }

    /**************************渲染类型和路径**************************/
    protected $renderType = RenderType.None;
    /** 渲染类型 */
    public get renderType() {
        return this.$renderType;
    }
    public set renderType(value) {
        if (this.$renderType !== value) {
            this._refreshRender = true;
        }
        this.$renderType = value;
    }

    protected $renderUrl = '';
    /**渲染路径(bundle:path) */
    public get renderUrl() {
        return this.$renderUrl;
    }
    public set renderUrl(value) {
        if (this.$renderUrl !== value) {
            this._refreshRender = true;
        }
        this.$renderUrl = value;
    }

    /**************************通用**************************/
    protected $offset = v3();
    /**位置偏移*/
    public get offset() {
        return this.$offset;
    }
    public set offset(value) {
        if (this.$offset !== value) {
            this._refreshAttr = true;
        }
        this.$offset.set(value);
    }

    protected $scale = v3(1, 1, 1);
    /**缩放 */
    public get scale() {
        return this.$scale;
    }
    public set scale(value) {
        if (this.$scale !== value) {
            this._refreshAttr = true;
        }
        this.$scale.set(value);
    }

    /**************************Prefab**************************/
    protected $prefabRenderData: Prefab = null;
    /**(prefab)渲染数据 */
    public get prefabRenderData() {
        return this.$prefabRenderData;
    }
    public set prefabRenderData(value) {
        this.$prefabRenderData = value;
        this._refreshRender = true;
    }

    /**************************图片**************************/
    protected $texRenderData: SpriteFrame = null;
    /**(图片)渲染数据 */
    public get texRenderData() {
        return this.$texRenderData;
    }
    public set texRenderData(value) {
        this.$texRenderData = value;
        this._refreshRender = true;
    }

    protected $texRenderType = Sprite.Type.SIMPLE;
    /**(图片)渲染方式 */
    public get texRenderType() {
        return this.$texRenderType;
    }
    public set texRenderType(value) {
        this.$texRenderType = value;
        this._refreshRenderAttr = true;
    }
    protected $texSizeMode = Sprite.SizeMode.RAW;
    /**(图片)尺寸方式 */
    public get texSizeMode() {
        return this.$texSizeMode;
    }
    public set texSizeMode(value) {
        this.$texSizeMode = value;
        this._refreshRenderAttr = true;
    }

    /**************************spine**************************/
    protected $spineRenderData: sp.SkeletonData = null;
    /**(spine)渲染数据 */
    public get spineRenderData() {
        return this.$spineRenderData;
    }
    public set spineRenderData(value) {
        this.$spineRenderData = value;
        this._refreshRender = true;
    }

    protected $spineSkin = '';
    /**(spine)皮肤 */
    public get spineSkin() {
        return this.$spineSkin;
    }
    public set spineSkin(value) {
        this.$spineSkin = value;
        this._refreshRenderAttr = true;
        this._refreshSpineSkin = true;
    }
    protected $spineAnimation = '';
    /**(spine)动作(如果要顺序执行一组动作, 将动作名以英文逗号分隔, 如: a,b,c) */
    public get spineAnimation() {
        return this.$spineAnimation;
    }
    public set spineAnimation(value) {
        this.$spineAnimation = value;
        this._refreshRenderAttr = true;
        this._refreshSpineAnimation = true;
    }
    protected $spinePaused = false;
    /**(spine)动作暂停 */
    public get spinePaused() {
        return this.$spinePaused;
    }
    public set spinePaused(value) {
        this.$spinePaused = value;
        this._refreshRenderAttr = true;
    }
    /**(spine)动作循环 */
    protected $spineLoop = true;
    public get spineLoop() {
        return this.$spineLoop;
    }
    public set spineLoop(value) {
        this.$spineLoop = value;
        this._refreshRenderAttr = true;
    }
    protected $spineAlpha = false;
    /**(spine)预乘 */
    public get spineAlpha() {
        return this.$spineAlpha;
    }
    public set spineAlpha(value) {
        this.$spineAlpha = value;
        this._refreshRenderAttr = true;
    }
    protected $spineTimeScale = 1;
    /**(spine)播放倍率 */
    public get spineTimeScale() {
        return this.$spineTimeScale;
    }
    public set spineTimeScale(value) {
        this.$spineTimeScale = value;
        this._refreshRenderAttr = true;
    }

    private _renderNode: Node = null;
    public get renderNode(): Node {
        if (!this._renderNode) {
            if (this.$renderType === RenderType.None) {
                this.error('设置renderType前无法获取renderNode');
                return null;
            }
            const parent = this.entity.node;

            this._renderNode = parent.getChildByName(`render:idle:${this.$renderType}`);
            if (this._renderNode) {
                this._renderNode.name = `render:used:${this.$renderType}`;
                this._renderNode.active = true;
            } else {
                this._renderNode = new Node(`render:used:${this.$renderType}`);
                this._renderNode.parent = parent;
            }

            this._renderNode.layer = Layers.Enum.UI_2D;
        }

        return this._renderNode;
    }

    /**
     * 渲染变更(这个回调渲染代表下载完成并已经实例化完毕，renderNode已经是完整的了)
     */
    protected onRenderChanged() { }

    protected onDisable() {
        super.onDisable();

        if (isValid(this._renderNode, true)) {
            this._renderNode.name = `render:idle:${this.$renderType}`;
            if (this.$renderType === RenderType.Spine) {
                this._renderNode.getComponent(sp.Skeleton).skeletonData = null;
            } else if (this.$renderType === RenderType.Texture) {
                this._renderNode.getComponent(Sprite).spriteFrame = null;
            } else {
                this._renderNode.destroyAllChildren();
            }
            this._renderNode.active = false;
            this._renderNode = null;
        }

        this.$offset.set(0, 0, 0);
        this.$scale.set(1, 1, 1);
        this.$renderType = RenderType.None;
        this.$renderUrl = '';
        this.$texRenderType = Sprite.Type.SIMPLE;
        this.$texSizeMode = Sprite.SizeMode.RAW;
        this.$spineSkin = '';
        this.$spineAnimation = '';
        this.$spinePaused = false;
        this.$spineLoop = true;
        this.$spineAlpha = false;
        this.$spineTimeScale = 1;
        this._refreshAttr = true;
        this._refreshRender = true;
        this._refreshSpineSkin = true;
        this._refreshRenderAttr = true;
        this._refreshSpineAnimation = true;
    }

    /**************************以下为系统调用**************************/
    static systemHandle(render: RenderComponent) {
        render._refreshAttr = false;
        render._refreshRender = false;
        render._refreshSpineSkin = false;
        render._refreshRenderAttr = false;
        render._refreshSpineAnimation = false;
    }

    static callRenderChanged(render: RenderComponent) {
        render.onRenderChanged();
    }
}